var EXPORTED_SYMBOLS = ["parse_handler"];

const LOCATION = "chrome://on-the-wave/content/PTTParser.js";
const LINEDIFF = 110;

var BBS = tabulator.ns.bbs; //the namespace for generating symbols we 
                            //defined, use, say, BBS('score')
//the rests are to be used in the say way, but they are standardized terms.
var RDF = tabulator.ns.rdf; //for rdf:type
var DCTERMS = tabulator.ns.dcterms; //for dcterms:title
var SIOC = tabulator.ns.sioc; //for sioc:has_container, sioc:has_owner, etc
                              //see <http://rdfs.org/sioc/spec/>
var RDFS = tabulator.ns.rdfs; // for rdfs:seeAlso
var FOAF = tabulator.ns.foaf; // for foaf:primaryTopic

var OWL = tabulator.ns.owl;
kb.add(FOAF('primaryTopic'), RDF('type'), OWL('FunctionalProperty'));

var tester = {
	test : function() {
	  	parse_handler.parse_post();
		this.check_any('board_name');
		this.check_any('post_title');
		this.check_any('post_time');
	},
	
	check_any : function (arg1) {
	  	var rel = kb.sym(arg1);
		var ret = kb.any(undefined, rel, parse_handler.symbol);
		if (!ret) {
			alert('Check ' + arg1 + 'with result: None');
		} else {
			alert('Check ' + arg1 + 'with result: ' + ret.uri);
		}  		
	},
}

var util = {
	mLog : '',
	Log : function (str) {
		this.mLog += str;
	},
	getLog : function () {
		var tmp = this.mLog;
		this.mLog = '';
		return tmp;
	},
	vocabulary: {
		post_title: "http://purl.org/dc/terms/title",
		post_time: "http://purl.org/dc/terms/created",
		board_name: "http://code.google.com/p/on-the-wave/voc#board_name",
		author_id: "http://code.google.com/p/on-the-wave/voc#author_id",
		author_nickname: "http://code.google.com/p/on-the-wave/voc#author_nickname",
		id_post_content: "http://code.google.com/p/on-the-wave/voc#id_post_content"
	},
	
	add_to_kb: function (arg1, arg2) {
    	//alert("add to kb: " + arg1 + " + " + arg2);
    	//kb.add(kb.sym(arg1), kb.sym(arg2), parse_handler.symbol);    
	    kb.add(parse_handler.symbol, kb.sym(this.vocabulary[arg2]), kb.literal(arg1));
	}
};

var parse_handler = {
	state : '',
	symbol : null,
	buffer : "",
	post_content : "",
	
	tag_value : function (tag) {
		var trim = /[^\s]+/;
		tag = trim.exec(tag);
		if (tag == "作者") return 0;
		if (tag == "看板") return 1;
		if (tag == "標題") return 2;
		if (tag == "時間") return 3;
	},

	parse_post : function(){
		function handle_post(tag) {		
			if (this.state == '') {			
				switch (this.tag_value(tag)) {
					case this.tag_value("作者"):
						this.state = 'author_id;author_nickname'; 
						break;
					case this.tag_value("看板"):					
						this.state = 'board_name'; 
						break;
					case this.tag_value("標題"):
						this.state = 'post_title'; 
						break;
					case this.tag_value("時間"):
						this.state = 'post_time'; 
						break;
					default:
						this.state = '';
						break;
				}
			} else if (this.state == 'id_post_content'){
				this.post_content += tag;
			} else {
				var ids = this.state.split(';');
				if (ids.length > 1) {
					var template = /^(.*?)\((.*?)\)/; //Case author (nickname)
					var tags = template.exec(tag);
					if (tags) {
						util.add_to_kb(tags[1], ids[0]);
						util.add_to_kb(tags[2], ids[1]);
					// kb.add(kb.sym(tags[0]), kb.sym(ids[0]), this.symbol);
					// kb.add(kb.sym(tags[1]), kb.sym(ids[1]), this.symbol);
					}							
				} else {
					util.add_to_kb(tag, this.state);				
				} 
				if (this.state == 'post_time') {
					this.state = 'id_post_content';
					this.post_content = "";
				} else {
					this.state = '';
				}					
			}
		} 
		try{
		var i = this.buffer.indexOf("[34;47m 作者");
		var ansi = this.buffer.substr(i); //remove misc info before 作者
		
		//var ansi = FireBBS.previous_ansi;
		ansi = ansi.replace(/\x07/g, '\x1B\x07');//escape BEL
		ansi = ansi.replace(/[\b]/g, '\x1B[1D');//escape BS(replace )
		ansi = ansi.replace(/\t/g, '\x1B[8C');//escape HT(replace )
		ansi = ansi.replace(/\n/g, '\x1B\n');//escape LF
		ansi = ansi.replace(/\v/g, '\x1B[6B');//escape VT(replace )
		ansi = ansi.replace(/\f/g, '\x1B[2J\x1B[H');//escape FF(replace )
		ansi = ansi.replace(/\r/g, '\x1B[1G');//escape CR(replace )
		
		var strArray = ansi.split('\x1B');
		for (var i = 0; i < strArray.length; i++) {
			switch (strArray[i][0]) {
				case '['://Functions using CSI
					var template = /^\x5B((?:|\d+|;)+)([\x40-\x5A\x60-\x7C])/;//Functions using CSI
					var result = template.exec(strArray[i]);
					if(result){							
						handle_post.call(this, strArray[i].substr(result[0].length));
					}
					break;
				case '\n':
					handle_post.call(this, "<br>" + strArray[i].substr(1));
					break;
			}
		}
		// Add the post content to kb.				
		util.add_to_kb(this.post_content, 'id_post_content');
		} catch (e) { handleException(e, LOCATION, LINEDIFF); }
	},

 parse_postlist: function parse_postlist(aStr){
    //aStr is conn.mScreenString sent from the BBS_BOARD state
    try{
      var theBoard = this.symbol;
      //a board is a forum
      kb.add(theBoard, RDF('type'), SIOC('Forum'));

      //讀出板主
      var boardOwnersStrArray = aStr.substring(aStr.indexOf("板主:")+3,
					       aStr.indexOf("】")).
                                     split('/');
      for (var i=0;i<boardOwnersStrArray.length;i++)
	kb.add(theBoard, SIOC('has_owner'),
	       kb.literal(boardOwnersStrArray[i]));
      //@@板主有...的時候

      aStr = aStr.substr(aStr.indexOf("】") + 1); //scan next 

      //讀出板標
      var boardNameRegexp = new RegExp("看板《.+?》 \n");
      var boardNameStart = aStr.search(boardNameRegexp);
      kb.add(theBoard, DCTERMS('title'),
	     aStr.substr(0, boardNameStart).trim());

      aStr = aStr.substr(aStr.indexOf('\n') + 1); //scan next

      //讀出人氣
      var visitorsRegexp = new RegExp("人氣:(\\d+)   \n");
      kb.add(theBoard, BBS('currentVisitors'),
	     parseInt(visitorsRegexp.exec(aStr)[1]));

      //讀出剩下的文章資料
      var articleLines = aStr.split('\n');
      //去除開頭兩行結束一行
      articleLines.shift();articleLines.shift();articleLines.pop();
      var firstArticleNumber = 0; //第一篇文章的編號 決定要不要繼續往上讀
      var starsNumber = 0; //置底文章數目
      var lastIndex = 0; //讀到文章的編號
      for (var line = articleLines.shift();line;
	   line = articleLines.shift()){
	if (!line.trim()) break; //空行
	var articleDataRegexp = new RegExp("^(?:●|  )(  ★ | *\\d+) ([ +~mMsS=!])([\\d ][\\d ]|爆|XX|X\\d)([\\d ]\\d/\\d\\d) (\\S+)(.+)$");
	var result = articleDataRegexp.exec(line);
	//@不要用正規表示比較快(?)

	var aArticle = kb.bnode(); //the node of the article
	kb.add(aArticle, SIOC('has_container'), theBoard);
	
	//文章的特殊狀況 被刪或是M文或是置底文
	var status = "";
	if (result[2] === "m" || result[2] === "M"){
	  status = 'elected';
	} else if (result[5] === "-") {
	  status = 'deleted';
	} else if (result[1] === "  ★ ") {
	  status = 'important';
	  starsNumber++;
	}
	if (status)
	  kb.add(aArticle, BBS('status'), status);

	if (status !== 'important'){
	  lastIndex = parseInt(result[1]);
          if (!firstArticleNumber) firstArticleNumber = lastIndex;
	  kb.add(aArticle, BBS('currentNumber'), lastIndex);
	} else {
	  //給置底文章一個*假的*currentNumber以便post_list.js排序
          //@全部是★的情形
	  kb.add(aArticle, BBS('currentNumber'), lastIndex + starsNumber);
	}
	
	//用一個*不太明確*的數字表示被推爆或是噓爆的文的推文數
	if (result[3] === "  "){
	  kb.add(aArticle, BBS('score'), 0);
	} else if (result[3] === "爆"){
	  kb.add(aArticle, BBS('score'), 100);
	} else if (result[3][0] === "X") {
	  if (result[3][1] === "X")
	    kb.add(aArticle, BBS('score'), -100);
	  else
	    kb.add(aArticle, BBS('score'), -10 * parseInt(result[3][1]));
	} else {
	  kb.add(aArticle, BBS('score'), parseInt(result[3]));
	}

        //把日期變成W3CDTF的標準格式
        var MD = result[4].split('/');
        var date = new Date();
        date.setMonth(parseInt(MD[0]));
        date.setDate(parseInt(MD[1]));
	kb.add(aArticle, DCTERMS('created'), W3CDTF_create(date));
        //@@這裡事實上是錯誤的時間 要考慮台灣的時間 != 世界的絕對時間

	kb.add(aArticle, BBS('author_id'), result[5]); //need not to trim
	//找出標題..@@注意到這個標題可能和內文不同...
	kb.add(aArticle, DCTERMS('title'), result[6].trim());
	//@@文章標題有...的時候

	//Meta data for identifying this article (Finding it's URI)
	if (result[5] !== "-" && !starsNumber){
	  //<bbs://ptt.cc/Gossiping/12345>, say
	  var aDoc = kb.sym(theBoard.uri + lastIndex.toString());
	  kb.add(aArticle, RDFS('seeAlso'), aDoc);
	  kb.add(aDoc, FOAF('primaryTopic'), aArticle);
	}
      }
      return firstArticleNumber;
    } catch (e) { 
      handleException(e, LOCATION, LINEDIFF); 
    }    
  },
 //called by the BBS connection
 feed: function feed(aStr){
    this.buffer += aStr;
  },
 
	flush: function flush(){
		this.parse_post();		
		this.buffer = "";
	}
};

//modified from <resource://gre/modules/ISO8601DateUtils.jsm>
function W3CDTF_create(aDate){
  function zeropad (s, l) {
    s = s.toString(); // force it to a string
    while (s.length < l) {
      s = '0' + s;
    }
    return s;
  }
  var result = zeropad(aDate.getUTCFullYear (), 4) +
               zeropad(aDate.getUTCMonth () + 1, 2) +
               zeropad(aDate.getUTCDate (), 2) + 'T' +
               zeropad(aDate.getUTCHours (), 2) + ':' +
               zeropad(aDate.getUTCMinutes (), 2) + ':' +
               zeropad(aDate.getUTCSeconds (), 2) + 'Z';

  return result;
}
